I am not understanding the ‘aligning allocated memory’ part from the mprotect usage.
I am referring to the code example given on http://linux.die.net/man/2/mprotect
char *p;
char c;
/* Allocate a buffer; it will have the default
protection of PROT_READ|PROT_WRITE. */
p = malloc(1024+PAGESIZE-1);
if (!p) {
perror("Couldn't malloc(1024)");
exit(errno);
}
/* Align to a multiple of PAGESIZE, assumed to be a power of two */
p = (char *)(((int) p + PAGESIZE-1) & ~(PAGESIZE-1));
c = p[666]; /* Read; ok */
p[666] = 42; /* Write; ok */
/* Mark the buffer read-only. */
if (mprotect(p, 1024, PROT_READ)) {
perror("Couldn't mprotect");
exit(errno);
}
For my understanding, I tried using a PAGESIZE of 16, and 0010 as address of p.
I ended up getting 0001 as the result of (((int) p + PAGESIZE-1) & ~(PAGESIZE-1)).
Could you please clarify how this whole ‘alignment’ works?
Thanks,
Assuming that
PAGESIZEis a power of 2 (a requirement), an integral value x can be rounded down to a multiple ofPAGESIZEwith(x & ~(PAGESIZE-1)). Similarly,((x + PAGESIZE-1) & ~(PAGESIZE-1))will result in x rounded up to a multiple ofPAGESIZE.For example, if
PAGESIZEis 16, then in binary with a 32-bit word:00000000000000000000000000010000PAGESIZE00000000000000000000000000001111PAGESIZE-111111111111111111111111111110000~(PAGESIZE-1)A bitwise-and (&) with the above value will clear the low 4 bits of the value, making it a multiple of 16.
That said, the code quoted in the description is from an old version of the manual page, and is not good because it wastes memory and does not work on 64-bit systems. It is better to use
posix_memalign()ormemalign()to obtain memory that is already properly aligned. The example on the current version of themprotect()manual page usesmemalign(). The advantage ofposix_memalign()is that it is part of the POSIX standard, and does not have different behavior on different systems like the older non-standardmemalign().