10

I came across following algorithm that aligns virtual address to immediate next page bounday.

VirtualAddr = (VirtualAddr & ~(PageSize-1));

Also, given a length of bytes aligns length (rounds it) to be on the page boundary

len = ((PageSize-1)&len) ? ((len+PageSize) & ~(PageSize-1)):len;

I am finding it hard to decipher how this works. Can someone help me out to break it down?

Steve H
  • 461
  • 2
  • 10
  • 18
  • 3
    That aligns a virtual address to the immediate _previous_ page boundry – Mooing Duck Apr 09 '14 at 18:13
  • ...and the second one doesn't work at all, unless there's other assumptions you haven't mentioned. (Oh wait, `if (len<=PageSize)` then it's `len`, otherwise it's len rounded up to the next page boundary. That's quite different than what you described. – Mooing Duck Apr 09 '14 at 18:16
  • Yes you are correct. 1. For first statement to align to immediate next boundary should be((VirtualAddr+PageSize) & ~(PageSize-1)) 2. And the second statement of the second line rounds to page size. – Steve H Apr 09 '14 at 18:50
  • 2
    Your correction to the first problem is _also_ incorrect (ish), as it adds unneeded padding to those already aligned; use `((VirtualAddr+PageSize-1) & ~(PageSize-1))` instead. – Mooing Duck Apr 09 '14 at 18:54
  • ```lang-py >>> hex(0x00053000 & ~(4095)) '0x53000' >>> hex(0x00053FFF & ~(4095)) '0x53000' >>> hex(0x00052FFF & ~(4095)) '0x52000' ``` – Keelung Sep 07 '20 at 17:16

3 Answers3

12

Those calculations assume that the page size is a power of 2 (which is the case for all systems that I know of), for example

PageSize = 4096 = 2^12 = 1000000000000 (binary)

Then (written as binary numbers)

PageSize-1    = 00...00111111111111
~(PageSize-1) = 11...11000000000000

which means that

(VirtualAddr & ~(PageSize-1))

is VirtualAddr with the lower 12 bits set to zero or, in other words, VirtualAddr rounded down to the next multiple of 2^12 = PageSize.

Now you can (hopefully) see that in

len = ((PageSize-1)&len) ? ((len+PageSize) & ~(PageSize-1)):len;

the first expression

 ((PageSize-1)&len)

is zero exactly if len is a multiple of PageSize. In that case, len is left unchanged. Otherwise (len + PageSize) is rounded down to the next multiple of PageSize.

So in any case, len is rounded up to the next multiple of PageSize.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Selecting this answer. Detailed, descriptive and exactly what I was looking for. Thanks everyone for helping me out :). – Steve H Apr 09 '14 at 18:55
3

I think the first one should be

VirtualAddr = (VirtualAddr & ~(PageSize-1)) + PageSize; 
a5hk
  • 7,532
  • 3
  • 26
  • 40
0

This one-liner will do it - if it is already aligned aligned it will not skip to the next page boundary:

aligned = ((unsigned long) a & (getpagesize()-1)) ? (void *) (((unsigned long) a+getpagesize()) & ~(getpagesize()-1)) : a;

This one-liner will do it - if it is already aligned aligned it will not skip to the next page boundary:

if you really do want to skip to the next page boundary even if it's already aligned - just do:

aligned = (void *) (((unsigned long) a+getpagesize()) & ~(getpagesize()-1))

This should avoid all compiler warnings, too.

getpagesize() is a POSIX thing. #include <unistd.h> to avoid warnings.

Brad
  • 11,262
  • 8
  • 55
  • 74